﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Interactivity;
using System.Windows.Controls.Primitives;

namespace ICodeShare.UI.Interactivity
{
    /// <summary>
    /// 占位符行为
    /// </summary>
    public class PlaceHolderBehavior : Behavior<TextBox>
    {
        #region 成员变量
        /// <summary>
        /// 占位符
        /// </summary>
        private TextBlock m_Text = new TextBlock();
        #endregion

        #region 依赖属性

        #region Text
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
            "Text"
            , typeof(string)
            , typeof(PlaceHolderBehavior)
            , new FrameworkPropertyMetadata("", new PropertyChangedCallback(TextPropertyChangedCallback))
            );
        /// <summary>
        /// Text
        /// </summary>
        public string Text
        {
            get
            {
                return (string)this.GetValue(TextProperty);
            }
            set
            {
                this.SetValue(TextProperty, value);
            }
        }
        private static void TextPropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender != null && sender is PlaceHolderBehavior)
            {
                PlaceHolderBehavior phb = (PlaceHolderBehavior)sender;
                phb.m_Text.Text = e.NewValue.ToString();
            }
        }
        #endregion

        #region FontSize
        public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
            "FontSize"
            , typeof(double?)
            , typeof(PlaceHolderBehavior)
            , new FrameworkPropertyMetadata(null, new PropertyChangedCallback(FontSizePropertyChangedCallback))
            );
        /// <summary>
        /// Text
        /// </summary>
        public double? FontSize
        {
            get
            {
                return (double?)this.GetValue(FontSizeProperty);
            }
            set
            {
                this.SetValue(FontSizeProperty, value);
            }
        }
        private static void FontSizePropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender != null && sender is PlaceHolderBehavior)
            {
                PlaceHolderBehavior phb = (PlaceHolderBehavior)sender;
                if (e.NewValue == null)
                    return;
                double dValue = double.Parse(e.NewValue.ToString());
                if (dValue >= 6 && dValue <= 72)
                    phb.m_Text.FontSize = dValue;
            }
        }
        #endregion

        #region Foreground
        public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
            "Foreground"
            , typeof(Brush)
            , typeof(PlaceHolderBehavior)
            , new FrameworkPropertyMetadata(null, new PropertyChangedCallback(ForegroundPropertyChangedCallback))
            );
        /// <summary>
        /// Foreground
        /// </summary>
        public Brush Foreground
        {
            get
            {
                return (Brush)this.GetValue(ForegroundProperty);
            }
            set
            {
                this.SetValue(ForegroundProperty, value);
            }
        }
        private static void ForegroundPropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender != null && sender is PlaceHolderBehavior)
            {
                PlaceHolderBehavior phb = (PlaceHolderBehavior)sender;
                if (e.NewValue == null)
                    return;
                phb.m_Text.Foreground = (Brush)e.NewValue;
            }
        }
        #endregion

        #region HorizontalAlignment
        public static readonly DependencyProperty HorizontalAlignmentProperty = DependencyProperty.Register(
            "HorizontalAlignment"
            , typeof(HorizontalAlignment?)
            , typeof(PlaceHolderBehavior)
            , new FrameworkPropertyMetadata(null, new PropertyChangedCallback(HorizontalAlignmentPropertyChangedCallback))
            );
        /// <summary>
        /// HorizontalAlignment
        /// </summary>
        public HorizontalAlignment? HorizontalAlignment
        {
            get
            {
                return (HorizontalAlignment?)this.GetValue(HorizontalAlignmentProperty);
            }
            set
            {
                this.SetValue(HorizontalAlignmentProperty, value);
            }
        }
        private static void HorizontalAlignmentPropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender != null && sender is PlaceHolderBehavior)
            {
                PlaceHolderBehavior phb = (PlaceHolderBehavior)sender;
                if (e.NewValue == null)
                    return;
                phb.m_Text.HorizontalAlignment = (HorizontalAlignment)e.NewValue;
            }
        }
        #endregion

        #region VerticalAlignment
        public static readonly DependencyProperty VerticalAlignmentProperty = DependencyProperty.Register(
            "VerticalAlignment"
            , typeof(VerticalAlignment?)
            , typeof(PlaceHolderBehavior)
            , new FrameworkPropertyMetadata(null, new PropertyChangedCallback(VerticalAlignmentPropertyChangedCallback))
            );
        /// <summary>
        /// VerticalAlignment
        /// </summary>
        public VerticalAlignment? VerticalAlignment
        {
            get
            {
                return (VerticalAlignment?)this.GetValue(VerticalAlignmentProperty);
            }
            set
            {
                this.SetValue(VerticalAlignmentProperty, value);
            }
        }
        private static void VerticalAlignmentPropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender != null && sender is PlaceHolderBehavior)
            {
                PlaceHolderBehavior phb = (PlaceHolderBehavior)sender;
                if (e.NewValue == null)
                    return;
                phb.m_Text.VerticalAlignment = (VerticalAlignment)e.NewValue;
            }
        }
        #endregion

        #region Margin
        public static readonly DependencyProperty MarginProperty = DependencyProperty.Register(
            "Margin"
            , typeof(Thickness?)
            , typeof(PlaceHolderBehavior)
            , new FrameworkPropertyMetadata(null, new PropertyChangedCallback(MarginPropertyChangedCallback))
            );
        /// <summary>
        /// Margin
        /// </summary>
        public Thickness? Margin
        {
            get
            {
                return (Thickness?)this.GetValue(MarginProperty);
            }
            set
            {
                this.SetValue(MarginProperty, value);
            }
        }
        private static void MarginPropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender != null && sender is PlaceHolderBehavior)
            {
                PlaceHolderBehavior phb = (PlaceHolderBehavior)sender;
                if (e.NewValue == null)
                    return;
                phb.m_Text.Margin = (Thickness)e.NewValue;
            }
        }
        #endregion

        #endregion

        #region 重写方法

        #region 注册事件
        /// <summary>
        /// 注册事件
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.Loaded += AssociatedObject_Loaded;
            this.AssociatedObject.TextChanged += AssociatedObject_TextChanged;
        }
        #endregion

        #region 注销事件
        /// <summary>
        /// 注销事件
        /// </summary>
        protected override void OnDetaching()
        {
            base.OnDetaching();
            this.AssociatedObject.Loaded -= AssociatedObject_Loaded;
            this.AssociatedObject.TextChanged -= AssociatedObject_TextChanged;
        }
        #endregion

        #endregion

        #region 事件

        #region Loaded
        /// <summary>
        /// Loaded
        /// </summary>
        void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
        {
            this.AssociatedObject.Loaded -= AssociatedObject_Loaded;
            if (this.FontSize == null)
                m_Text.FontSize = this.AssociatedObject.FontSize;
            if (this.Foreground == null)
                m_Text.Foreground = this.AssociatedObject.Foreground;
            if (this.HorizontalAlignment == null)
                m_Text.HorizontalAlignment = this.AssociatedObject.HorizontalContentAlignment;
            if (this.VerticalAlignment == null)
                m_Text.VerticalAlignment = this.AssociatedObject.VerticalContentAlignment;
            if (this.Margin == null)
                m_Text.Margin = new Thickness(3, 0, 0, 0);

            if (!string.IsNullOrEmpty(this.AssociatedObject.Text))
                m_Text.Visibility = Visibility.Hidden;

            FrameworkElement host = (FrameworkElement)FindChildNode(this.AssociatedObject, "PART_ContentHost");
            DependencyObject parent = VisualTreeHelper.GetParent(host);
            //Decorator Panel
            if (parent.GetType().IsSubclassOf(typeof(Decorator)))
            {
                Decorator decParent = parent as Decorator;
                decParent.Child = null;

                Grid grid = new Grid();
                grid.Children.Add(host);
                grid.Children.Add(m_Text);
                decParent.Child = grid;
            }
            if (parent.GetType().IsSubclassOf(typeof(Panel)))
            {
                Panel pnlParent = parent as Panel;
                int index = pnlParent.Children.IndexOf(host);
                pnlParent.Children.Remove(host);

                Grid grid = new Grid();
                grid.Children.Add(host);
                grid.Children.Add(m_Text);

                pnlParent.Children.Insert(index, grid);

                if (parent.GetType() == typeof(Grid))
                {
                    Grid.SetColumn(grid, Grid.GetColumn(host));
                    Grid.SetRow(grid, Grid.GetRow(host));
                }
                if (parent.GetType() == typeof(DockPanel))
                {
                    DockPanel.SetDock(grid, DockPanel.GetDock(host));
                }
                if (parent.GetType() == typeof(Canvas))
                {
                    Canvas.SetLeft(grid, Canvas.GetLeft(host));
                    Canvas.SetTop(grid, Canvas.GetTop(host));
                }
            }
        }
        #endregion

        #region TextChanged
        /// <summary>
        /// TextChanged
        /// </summary>
        void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (this.AssociatedObject.Text.Length == 0)
            {
                m_Text.Visibility = Visibility.Visible;
            }
            else
            {
                if (m_Text.Visibility != Visibility.Hidden)
                    m_Text.Visibility = Visibility.Hidden;
            }
        }
        #endregion

        #endregion

        #region 方法

        #region 获取子节点
        /// <summary>
        /// 获取子节点
        /// </summary>
        /// <param name="reference">容器</param>
        /// <param name="elementName">名称</param>
        /// <returns>DependencyObject</returns>
        private DependencyObject FindChildNode(DependencyObject reference, string elementName)
        {
            int childCount = VisualTreeHelper.GetChildrenCount(reference);
            if (childCount == 0)
                return null;

            for (int i = 0; i < childCount; i++)
            {
                DependencyObject dObj = VisualTreeHelper.GetChild(reference, i);
                if (dObj.GetType().IsSubclassOf(typeof(FrameworkElement)))
                {
                    FrameworkElement fe = (FrameworkElement)dObj;
                    if (fe.Name == elementName)
                    {
                        return dObj;
                    }
                }
                DependencyObject childDObj = FindChildNode(dObj, elementName);
                if (childDObj == null)
                    continue;
                else
                    return childDObj;
            }
            return null;
        }
        #endregion

        #endregion
    }
}
